#include "Parameters.h"
#include <string>
#include <ctime>
#include <direct.h> // For _mkdir()
#include <io.h>   // For _access().

#include <sstream>
#include <fstream>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
#define DiffTime 3
float round(double val, int digits)
{
	double mult = pow(10.0, digits);
	return floorf(val * mult + 0.5) / mult; 
}

void createDirectory(string directory)
{
	if ( _access( directory.c_str(), 0 ))
		_mkdir (directory.c_str());
}


int hexaToInt(string shex){
	int ans;
	stringstream hex(shex);
	hex >> std::hex >> ans;
	return ans;
}
vector<string> splitLine (string str, char delimiter)
{
	vector<string> ans;
	stringstream ss (str);
	int length = str.length();
	char *a=new char[str.size()+1];
	while (ss.good() )
	{
		ss.getline(a, length, delimiter);
		if (strlen(a)==0)
			continue;
		ans.push_back(string(a));
	}
	delete [] a;
	return ans;
}


bool isSequential(double time, int lunID, int offset, map<string,pair<double,bool>>* extents)
{
	stringstream s;
	s << lunID << "," << offset;
	if (extents->at(s.str()).second && ((time - extents->at(s.str()).first) < DiffTime))
		return true;
	int count = 0;
	for (int i = -2 ; i < 3; i++)
	{
		count++;
		s = stringstream();
		s << lunID << "," << (offset+i);
		string extentID = s.str();
		if (extents->find(extentID) == extents->end())
			count = 0;
		if (time - extents->find(extentID)->second.first > DiffTime)
			count = 0;
		if (count == 3)
			return true;
	}
	return false;
}

void markAsSequential(double time, int lunID, int offset, map<string,pair<double,bool>>* extents)
{
	stringstream s;
	s << lunID << "," << offset;
	extents->at(s.str()).first = time;
	extents->at(s.str()).second = true;
	for (int i = -2 ; i < 3; i++)
	{
		s = stringstream();
		s << lunID << "," << (offset+i);
		string extentID = s.str();
		if (extents->find(extentID) != extents->end())
			extents->at(s.str()).second = true;
	}
}
void insert(double time, string extentId, map<string,pair<double,bool>>* extents)
{
	if (extents->find(extentId) == extents->end())
	{
		extents->insert(make_pair(extentId, make_pair(time,false)));
	}

}
void writeStatistics(ofstream& out, int align, map<string,pair<double,bool>>* extents)
{
	double count = 0;
	for (map<string,pair<double,bool>>::iterator it = extents->begin(); it != extents->end(); it++)
		if (it->second.second)
			count++;
	out << "Total extents:," << extents->size() << ",Total sequential:," << count << ",Sequential rate:," << (count/extents->size()) << endl;
	out << "Lun ID,Offset" << endl;
	for (map<string,pair<double,bool>>::iterator it = extents->begin(); it != extents->end(); it++)
	{
		if (it->second.second)
		{
			vector<string> parts = splitLine(it->first, ',');
			int offset = atoi(parts[1].c_str())*align;
			out << parts[0] << "," << offset << endl;
		}
	}
	
}
// this function write to file several statistics about the file given as parameter such as sequential rate
void explore(string path, string file)
{
	ifstream in(path + file);
	if (!in)
	{
		cout << "input file not open" << endl;
		exit(-1);
	}
	ofstream out8KB(path + "stat8KB-" + file + ".csv", ios::trunc);
	
	map<string,pair<double,bool>>* extents8KB = new map<string,pair<double,bool>>();
	int x = 0;
	while (in)
	{
		string line;
		getline(in, line);
		if (line.size() == 0)
			continue;
		vector<string> parts=splitLine(line, ' ');
		if (parts.size() != 6)
			continue;

		double dataTime = atof(parts.at(0).c_str());
		if (dataTime < 0 ) 
			continue;

		if (x++ == 100000)
		{
			cout << "time is: " << dataTime << endl;
			x = 0;
		}
		int lunId = hexaToInt(parts.at(3));
		int offset = atoi(parts.at(4).c_str());
		int offset8KB = (long)(floor((offset / 2.0)/ 8));
	
		stringstream s;
		s << lunId << "," << offset8KB;
		string extentID8KB = s.str();
		
		// insert extentId if doesn't exist already
		insert(dataTime, extentID8KB, extents8KB);
		
		if (isSequential(dataTime, lunId, offset8KB, extents8KB))
			markAsSequential(dataTime, lunId, offset8KB, extents8KB);
	}
	writeStatistics(out8KB, 8, extents8KB);
	
	delete extents8KB;
	in.close();
	out8KB.close();
}

int main2()
{
	string file;
	ifstream f ("E:/InputFiles/Config/fileName.txt");
	f >> file;
	explore("E:/InputFiles/Data/" ,file);
	return 0;
}